package com.dragon.english_practice_back.service.impl;

import cn.hutool.json.JSONUtil;
import com.dragon.english_practice_back.entity.AIJson.TranslateQuestion;
import com.dragon.english_practice_back.enums.TranslateQuestionType;
import com.dragon.english_practice_back.service.GenerateExerciseService;
import com.dragon.english_practice_back.enums.RedisPrefixEnum;
import com.dragon.english_practice_back.service.PromptRefineFactory;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
import org.springframework.ai.deepseek.api.ResponseFormat;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@EnableAsync
@Slf4j
@AllArgsConstructor
public class GenerateExerciseServiceImpl implements GenerateExerciseService {
    @Value("${translate.exercise.batch-size:10}")
    private static final int BATCH_SIZE = 10;
    private RedissonClient redissonClient;
    private RedisTemplate<String, TranslateQuestion> redisTemplate;
    private PromptRefineFactory promptRefineFactory;
    private TokenUsageServiceImpl tokenUsageServiceImpl;
    private ChatClient deepSeekChatClient;

    @Override
    @Async
    public void asyncRefillQuestions(int id, TranslateQuestionType type) {
        RLock lock = null;
        if (type == TranslateQuestionType.English_Chinese_Translation) {
            lock = redissonClient.getLock(RedisPrefixEnum.ENGLISH_CHINESE_TRANSLATE_LOCK.getPrefix() + id);
        }
        else if (type == TranslateQuestionType.Chinese_English_Translation) {
            lock = redissonClient.getLock(RedisPrefixEnum.CHINESE_ENGLISH_TRANSLATE_LOCK.getPrefix() + id);
        }
        try {
            log.debug("tryLock for userId:{}", id);
            // 尝试加锁（等待0秒，锁定300秒）
            if (lock != null && lock.tryLock(0, 300, TimeUnit.SECONDS)) {
                log.debug("start for userId:{} generate translate exercise", id);
                // 获取当前系统时间用于计时
                LocalDateTime startTime = LocalDateTime.now();

                String systemPrompt = """
                你是一个英语翻译题目生成助手,你的输出格式为JSON,题目中不允许出现emoji
                输出格式示例为:
                {
                    "questions" : [{
                        "question": "题目1",
                        "standardAnswer": "答案1"
                    },
                    {
                        "question": "题目2",
                        "standardAnswer": "答案2"
                    }]
                }
                你可以生成英译中或中译英的题目,这个由用户决定,如果用户没有指定题目类型,则默认生成英译中题目。
                你不需要在题目中指出这是英译中还是中译英,你只需要生成题目即可。
                你生成的题目数量由用户决定,题目难度由用户决定,如果用户没有指定题目数量,则默认生成5个题目。
                用户可能会要求你在翻译题目中插入他的不熟悉单词，如果有不熟悉单词则在题目中插入不熟悉单词，要确保题目的语义正确。
                """;
                // 插入不熟悉单词
                systemPrompt = promptRefineFactory.addStrangeWord(id, systemPrompt);
                // 插入不熟悉语法
                systemPrompt = promptRefineFactory.addGrammar(id, systemPrompt);

                // 调用AI接口生成题目
                Message systemMessage = new SystemMessage( systemPrompt);
                Message userMessage = new UserMessage("");
                if (type == TranslateQuestionType.Chinese_English_Translation) {
                    userMessage = new UserMessage("给我"+ BATCH_SIZE + "道英语练习题" + "\n题目的类型要中译英的");
                }
                if (type == TranslateQuestionType.English_Chinese_Translation) {
                    userMessage = new UserMessage("给我"+ BATCH_SIZE + "道英语练习题" + "\n题目的类型要英译中的");
                }

                String result = this.deepSeekChatClient.prompt().messages(List.of(systemMessage, userMessage))
                        .options(DeepSeekChatOptions.builder()
                                .temperature(1.3)
                                .responseFormat(ResponseFormat.builder()
                                        .type(ResponseFormat.Type.JSON_OBJECT)
                                        .build())
                                .build()
                        )
                        .call().content();

                log.debug("aiResult: {}", result);
                List<TranslateQuestion> questions = new ArrayList<>();
                if (result != null) {
                    log.debug("originContent: {}", result);
                    // 检查是否为JSON格式
                    if (JSONUtil.isTypeJSON(result)) {
                        questions.addAll(JSONUtil.parseObj(result).getBeanList("questions", TranslateQuestion.class));
                    } else {
                        log.debug("originContent not json");
                    }
                }

                // 计算生成题目所需时间
                LocalDateTime generateQuestionTime = LocalDateTime.now();
                long duration = ChronoUnit.MILLIS.between(startTime, generateQuestionTime);
                log.debug("generate questions cost {} Millis for userId: {}", duration, id);

                // 批量保存到Redis
                if (!questions.isEmpty()) {
                    // 通过type判断是英译中还是中译英
                    if (type == TranslateQuestionType.English_Chinese_Translation) {
                        redisTemplate.opsForList().rightPushAll(
                                RedisPrefixEnum.ENGLISH_CHINESE_TRANSLATE_QUEUE.getPrefix() + id,
                                questions
                        );
                    }
                    else {
                        redisTemplate.opsForList().rightPushAll(
                                RedisPrefixEnum.CHINESE_ENGLISH_TRANSLATE_QUEUE.getPrefix() + id,
                                questions
                        );
                    }
                }

                // 计算保存到Redis所需时间
                LocalDateTime saveToRedisTime = LocalDateTime.now();
                duration = ChronoUnit.MILLIS.between(generateQuestionTime, saveToRedisTime);
                log.debug("save to redis cost {} Millis for userId: {}", duration, id);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
